/**
 * @license AngularJS v1.2.4
 * (c) 2010-2014 Google, Inc. http://angularjs.org
 * License: MIT
 */
(function (window, angular, undefined) {
    'use strict';

    /**
     * @ngdoc overview
     * @name ngCookies
     * @description
     *
     * # ngCookies
     *
     * The `ngCookies` module provides a convenient wrapper for reading and writing browser cookies.
     *
     * {@installModule cookies}
     *
     * <div doc-module-components="ngCookies"></div>
     *
     * See {@link ngCookies.$cookies `$cookies`} and
     * {@link ngCookies.$cookieStore `$cookieStore`} for usage.
     */


    angular.module('ngCookies', ['ng']).
    /**
     * @ngdoc object
     * @name ngCookies.$cookies
     * @requires $browser
     *
     * @description
     * Provides read/write access to browser's cookies.
     *
     * Only a simple Object is exposed and by adding or removing properties to/from
     * this object, new cookies are created/deleted at the end of current $eval.
     *
     * Requires the {@link ngCookies `ngCookies`} module to be installed.
     *
     * @example
     <doc:example>
     <doc:source>
     <script>
     function ExampleController($cookies) {
           // Retrieving a cookie
           var favoriteCookie = $cookies.myFavorite;
           // Setting a cookie
           $cookies.myFavorite = 'oatmeal';
         }
     </script>
     </doc:source>
     </doc:example>
     */
    factory('$cookies', ['$rootScope', '$browser', function ($rootScope, $browser) {
        var cookies = {},
            lastCookies = {},
            lastBrowserCookies,
            runEval = false,
            copy = angular.copy,
            isUndefined = angular.isUndefined;

        //creates a poller fn that copies all cookies from the $browser to service & inits the service
        $browser.addPollFn(function () {
            var currentCookies = $browser.cookies();
            if (lastBrowserCookies != currentCookies) { //relies on browser.cookies() impl
                lastBrowserCookies = currentCookies;
                copy(currentCookies, lastCookies);
                copy(currentCookies, cookies);
                if (runEval) $rootScope.$apply();
            }
        })();

        runEval = true;

        //at the end of each eval, push cookies
        //TODO: this should happen before the "delayed" watches fire, because if some cookies are not
        //      strings or browser refuses to store some cookies, we update the model in the push fn.
        $rootScope.$watch(push);

        return cookies;


        /**
         * Pushes all the cookies from the service to the browser and verifies if all cookies were
         * stored.
         */
        function push() {
            var name,
                value,
                browserCookies,
                updated;

            //delete any cookies deleted in $cookies
            for (name in lastCookies) {
                if (isUndefined(cookies[name])) {
                    $browser.cookies(name, undefined);
                }
            }

            //update all cookies updated in $cookies
            for (name in cookies) {
                value = cookies[name];
                if (!angular.isString(value)) {
                    if (angular.isDefined(lastCookies[name])) {
                        cookies[name] = lastCookies[name];
                    } else {
                        delete cookies[name];
                    }
                } else if (value !== lastCookies[name]) {
                    $browser.cookies(name, value);
                    updated = true;
                }
            }

            //verify what was actually stored
            if (updated) {
                updated = false;
                browserCookies = $browser.cookies();

                for (name in cookies) {
                    if (cookies[name] !== browserCookies[name]) {
                        //delete or reset all cookies that the browser dropped from $cookies
                        if (isUndefined(browserCookies[name])) {
                            delete cookies[name];
                        } else {
                            cookies[name] = browserCookies[name];
                        }
                        updated = true;
                    }
                }
            }
        }
    }]).


    /**
     * @ngdoc object
     * @name ngCookies.$cookieStore
     * @requires $cookies
     *
     * @description
     * Provides a key-value (string-object) storage, that is backed by session cookies.
     * Objects put or retrieved from this storage are automatically serialized or
     * deserialized by angular's toJson/fromJson.
     *
     * Requires the {@link ngCookies `ngCookies`} module to be installed.
     *
     * @example
     */
    factory('$cookieStore', ['$cookies', function ($cookies) {

        return {
            /**
             * @ngdoc method
             * @name ngCookies.$cookieStore#get
             * @methodOf ngCookies.$cookieStore
             *
             * @description
             * Returns the value of given cookie key
             *
             * @param {string} key Id to use for lookup.
             * @returns {Object} Deserialized cookie value.
             */
            get: function (key) {
                var value = $cookies[key];
                return value ? angular.fromJson(value) : value;
            },

            /**
             * @ngdoc method
             * @name ngCookies.$cookieStore#put
             * @methodOf ngCookies.$cookieStore
             *
             * @description
             * Sets a value for given cookie key
             *
             * @param {string} key Id for the `value`.
             * @param {Object} value Value to be stored.
             */
            put: function (key, value) {
                $cookies[key] = angular.toJson(value);
            },

            /**
             * @ngdoc method
             * @name ngCookies.$cookieStore#remove
             * @methodOf ngCookies.$cookieStore
             *
             * @description
             * Remove given cookie
             *
             * @param {string} key Id of the key-value pair to delete.
             */
            remove: function (key) {
                delete $cookies[key];
            }
        };

    }]);


})(window, window.angular);
